<?php
    class Rcon {
        private $socket;
        private $outtime;
        private $loginis = false;
        public $erris = false;
        public $errstr;
        public $errno;

        public function __construct($host,$port,$rcon_pwd,$outtime) {

            $this->outtime = $outtime;

            //连接Rcon服务器
            $this->socket = @stream_socket_client("tcp://$host:$port",$errno,$errstr,$this->outtime);

            if ($this->socket === false) {
                $this->erris = true;
                $this->errstr = $errstr;
                $this->errno = $errno;
                return;
            }

            //连接成功，尝试登录
            $this->login($rcon_pwd);
        }

        private function login($pwd) {
            //合成RCON请求包
            $data_id = [mt_rand(10,99),mt_rand(10,99),mt_rand(10,99),mt_rand(10,99)];
            $send_data = hex2bin($this->decToHexWithLeadingZero(strlen($pwd)+10))."\0\0\0".hex2bin($data_id[0]).hex2bin($data_id[1]).hex2bin($data_id[2]).hex2bin($data_id[3])."\x03\0\0\0".$pwd."\0\0";
            $byteStr = $this->send_data($send_data);
            if ($byteStr == false) {
                return false;
            }
            $new_data_id = substr($byteStr,8,8);
            $new_mode = substr($byteStr,16,2);
            if ($new_mode == '02') {
                if ($new_data_id == 'ffffff') {
                    $this->erris = true;
                    $this->errstr = 'Login not';
                    $this->errno = 2;
                    return false;
                }
            } else {
                $this->erris = true;
                $this->errstr = 'Data Error';
                $this->errno = 3;
                return false;
            }
            $this->loginis = true;
        }

        private function send_data($data) {
            fwrite($this->socket,$data);
            $response = fread($this->socket,4096);
            if ($response === false or $response == '') {
                $this->erris = true;
                $this->errstr = 'Not Data or Time Out';
                $this->errno = 1;
                return false;
            }
            $byteStr = bin2hex($response);
            return $byteStr;
        }

        public function sendcommand($command) {
            if (!$this->loginis) {
                $this->erris = true;
                $this->errstr = "Don't Login";
                $this->errno = 0;
                return false;
            }

            //合成数据包
            $data_id = [mt_rand(10,99),mt_rand(10,99),mt_rand(10,99),mt_rand(10,99)];
            $send_data = hex2bin($this->decToHexWithLeadingZero(strlen($command)+10))."\0\0\0".hex2bin($data_id[0]).hex2bin($data_id[1]).hex2bin($data_id[2]).hex2bin($data_id[3])."\x02\0\0\0".$command."\0\0";
            $byteStr = $this->send_data($send_data);
            if ($byteStr == false) {
                return false;
            }
            $printis = substr($byteStr,0,2);
            if ($printis == '0a') {
                return true;
            } else {
                $returnmsg = substr($byteStr,24);
                $returnmsg = substr($returnmsg,0,-4);
                $returnmsg = $this->hexToAscii($returnmsg);
                return $returnmsg;
            }
        }

        private function hexToAscii($hexStr) {  
            $asciiStr = '';
            $len = strlen($hexStr);  
            for ($i = 0; $i < $len; $i += 2) {  
                $substr = $hexStr[$i] . $hexStr[$i + 1];  
                $asciiStr .= chr(hexdec($substr));  
            }  
            return $asciiStr;  
        }  

        private function decToHexWithLeadingZero($dec) {  
            $hex = dechex($dec);  
            // 如果十六进制字符串长度小于2，则在其前面添加'0'  
            if (strlen($hex) < 2) {  
                $hex = '0' . $hex;  
            }  
            return $hex;  
        }  

        public function close() {
            if (!$this->loginis) {
                $this->erris = true;
                $this->errstr = "Don't Login";
                $this->errno = 0;
                return false;
            }
            fclose($this->socket);
            $this->loginis = false;
            return true;
        }

        public function __destruct() {  
            if (!$this->close()) {
                return false;
            }
        }  
    }
?>